#pragma once

#include "Logger.hpp"
#include <iostream>
#include <string>
#include <unordered_map>

static const std::string linesep = "\r\n";
static const std::string linesep1 = " ";
static const std::string linesep2 = ": ";
static const std::string webroot = "./wwwroot";
static const std::string defaulthome = "index.html";
static const std::string html_404 = "404.html";
static const std::string suffixsep = ".";

class HttpRequest
{
private:
    std::string ReqOneLine(std::string &reqstr, bool *status)
    {
        auto pos = reqstr.find(linesep);
        if (pos == std::string::npos)
        {
            *status = false;
            return std::string();
        }
        *status = true;
        auto line = reqstr.substr(0, pos);
        reqstr.erase(0, pos + linesep.size());

        return line;
    }
    void ParseReqLine(std::string &reqline)
    {
        std::stringstream ss(reqline);
        ss >> _methon >> _uri >> _httpversion;
    }
    void BuildKV(std::string line, std::string *k, std::string *v)
    {
        auto pos = line.find(linesep2);
        if (pos == std::string::npos)
        {
            *k = *v = std::string();
            return;
        }
        *k = line.substr(0, pos);
        *v = line.substr(pos + linesep2.size());
    }

public:
    HttpRequest() {}
    // 接收请求不做序列化，只做反序列化
    bool Deserialize(std::string &reqstr)
    {
        // 1. 先取出报文的第一行(请求行)
        bool status = true;
        std::string reqline = ReqOneLine(reqstr, &status);
        if (reqline.empty())
            return false;
        // 将获取的报文第一行的各个数据分别取出来
        ParseReqLine(reqline);
        // 2. 循环取出请求报头
        while (true)
        {
            status = true;
            // 循环一行行的取出报头
            reqline = ReqOneLine(reqstr, &status);
            // 判断状态是不是true且reqline是否为空
            if (status && !reqline.empty())
            {
                std::string k, v;
                // 将截出的报头k,v分开
                BuildKV(reqline, &k, &v);
                _req_headers.insert(std::make_pair(k, v));
            }
            else if (status)
            {
                // 走到这里说明，已经将请求报头取出
                // 3. 取出空行
                _blank_line = linesep;
                break;
            }
            else
            {
                return false;
            }
        }
        // 走到这里说明只剩下请求正文了
        // 4. 取出请求正文
        _req_body = reqstr;

        // 判断路径
        _path = webroot;
        _path += _uri;
        if (_uri == "/")
        {
            // 如果是直接访问web根目录直接进入首页
            _path += defaulthome;
        }
        LOG(LogLevel::DEBUG) << "path: " << _path;

        return true;
    }
    std::string Path()
    {
        return _path;
    }
    std::string Body()
    {
        return _req_body;
    }
    // 提取文件后缀
    std::string Suffix()
    {
        if (_path.empty())
            return std::string();

        auto pos = _path.rfind(suffixsep);
        if (pos == std::string::npos)
            return std::string();
        std::string line = _path.substr(pos);

        return line;
    }
    ~HttpRequest() {}

private:
    std::string _methon; // 请求方法
    std::string _uri;
    std::string _httpversion;                                  // http版本
    std::unordered_map<std::string, std::string> _req_headers; // 请求报头
    std::string _blank_line;
    std::string _req_body; // 请求正文

    std::string _path; // 真正需要访问的资源路径
};

class HttpResponse
{
private:
    // 状态码对应的状态码描述
    std::string Code2Desc(int code)
    {
        switch (code)
        {
        case 200:
            return "OK";
        case 400:
            return "Bad Request";
        case 404:
            return "Not Found";
        case 301:
            return "Moved Permanently";
        case 302:
            return "See Other";
        case 307:
            return "Temporary Redirect";
        default:
            return "";
        }
    }

public:
    // 默认http版本为HTTP/1.1
    HttpResponse()
        : _httpversion("HTTP/1.1"),
          _blank_line(linesep)
    {
    }
    // 接收响应不做反序列化，只做序列化
    std::string Serialize()
    {
        // 构建响应协议第一行(状态行)
        std::string respstr = _httpversion + linesep1 + std::to_string(_code) +
                              linesep1 + _desc + linesep;
        // 有效载荷报头
        if (!_resp_body.empty())
        {
            std::string len = std::to_string(_resp_body.size());
            SetHeader("Content-Length", len);
        }
        // 响应报头
        for (auto &elme : _resp_headers)
        {
            std::string line = elme.first + linesep2 + elme.second + linesep;
            respstr += line;
        }
        // 空行 & 响应正文
        respstr += _blank_line;
        respstr += _resp_body;

        return respstr;
    }
    bool ReadContent(const std::string &path)
    {
        // 以二级制方式读取
        // 打开文件，二进制模式
        std::ifstream file(path, std::ios::binary);
        if (!file.is_open())
        {
            LOG(LogLevel::WARNING) << path << " 资源不存在!";
            return false;
        }

        // 定位到文件末尾获取文件大小
        file.seekg(0, std::ios::end);
        std::streampos fileSize = file.tellg(); // 获取文件大小
        file.seekg(0, std::ios::beg);

        // 创建足够大的字符串来保存数据
        _resp_body.resize(static_cast<size_t>(fileSize));

        // 读取文件内容到字符串
        file.read(&_resp_body[0], fileSize);
        file.close();

        return true;
    }
    void SetCode(int code)
    {
        if (code >= 100 && code <= 600)
        {
            _code = code;
            _desc = Code2Desc(code);
        }
        else
        {
            LOG(LogLevel::DEBUG) << "非法的状态码: " << code;
        }
    }
    // 添加报头
    bool SetHeader(const std::string &key, const std::string &value)
    {
        // unordered_map中重载了[]
        // 所以当key不存在，则插入key & value
        // 如果key存在，则value替代老的key中的value
        _resp_headers[key] = value;

        return true;
    }

    ~HttpResponse() {}

private:
    std::string _httpversion;
    int _code;         // 状态码
    std::string _desc; // 状态码描述
    std::unordered_map<std::string, std::string> _resp_headers;
    std::string _blank_line;
    std::string _resp_body;
};

class Http
{
public:
    Http() {}
    // 获取文件数据类型
    std::string Suffix2Desc(const std::string &suffix)
    {
        if (suffix == ".html")
            return "text/html";
        else if (suffix == ".css")
            return "text/css";
        else if (suffix == ".js")
            return "application/x-javascript";
        else if (suffix == ".png")
            return "image/png";
        else if (suffix == ".jpg")
            return "image/jpeg";
        else if (suffix == ".txt")
            return "text/plain";
        else
            return "text/html";
    }
    std::string HandlerRequst(std::string &requeststr)
    {
        std::string respstr;
        HttpRequest req;
        // 请求应答反序列化
        if (req.Deserialize(requeststr))
        {
            HttpResponse resp;
            // 找到制定路径下的资源，进行读取
            // 这里需要注意的是，需要进行二进制的读取，不像之前read，write解决
            if (resp.ReadContent(req.Path()))
            {
                // 有资源
                std::string suffix = req.Suffix();
                std::string mime_type_value = Suffix2Desc(suffix);
                resp.SetHeader("Content-Type", mime_type_value);
                resp.SetCode(200);
            }
            else
            {
                resp.SetCode(302);
                //重定向，更改location，location指的是上次的地址
                //设置成'/'说明假设不是上面获取的地址,就会跳转到Location内指定的地址
                //因为它以响应报头的形式传给对端
                resp.SetHeader("Location","/404.html");
            }
            // 响应应答序列化
            respstr = resp.Serialize();
        }
        return respstr;
    }
    ~Http() {}

private:
};